﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace Microsoft.Phone.UserData
{
	/// <summary>
	/// Provides <see langword="static"/> factory methods for searching <see cref="Contacts"/> and <see cref="Appointments"/>.
	/// </summary>
	public static class ObservableUserData
	{
		#region Public Properties
		/// <summary>
		/// Gets a sequence of <see cref="Account"/> objects containing the contacts that <see cref="SearchContacts"/> searches.
		/// </summary>
		public static IEnumerable<Account> ContactAccounts
		{
			get
			{
				return Contacts.Accounts;
			}
		}

		/// <summary>
		/// Gets a sequence of <see cref="Account"/> objects containing appointments that can be searched.
		/// </summary>
		public static IEnumerable<Account> AppointmentAccounts
		{
			get
			{
				return Appointments.Accounts;
			}
		}
		#endregion

		#region Private / Protected
		private static Contacts Contacts
		{
			get
			{
				Contract.Ensures(Contract.Result<Contacts>() != null);

				var value = contacts.Value;

				Contract.Assume(value != null);

				return value;
			}
		}

		private static Appointments Appointments
		{
			get
			{
				Contract.Ensures(Contract.Result<Appointments>() != null);

				var value = appointments.Value;

				Contract.Assume(value != null);

				return value;
			}
		}

		private static readonly Lazy<Contacts> contacts = new Lazy<Contacts>(() => new Contacts());
		private static readonly Lazy<Appointments> appointments = new Lazy<Appointments>(() => new Appointments());
		#endregion

		#region Methods
		/// <summary>
		/// Asynchronously searches for contacts in the user’s contact data.
		/// </summary>
		/// <param name="filter">The filter to use to search for contacts.</param>
		/// <param name="filterKind">The kind of filter to use when searching for contacts.</param>
		/// <returns>A singleton observable sequence containing the search results.</returns>
		public static IObservable<ContactsSearchEventArgs> SearchContacts(string filter, FilterKind filterKind)
		{
			Contract.Ensures(Contract.Result<IObservable<ContactsSearchEventArgs>>() != null);

			return Contacts.SearchObservable(filter, filterKind);
		}

		/// <summary>
		/// Asynchronously searches for appointments that occur between the specified start date and time and end date and time.
		/// </summary>
		/// <param name="startTimeInclusive">The start date and time to use to search for appointments.</param>
		/// <param name="endTimeInclusive">The end date and time to use to search for appointments.</param>
		/// <returns>A singleton observable sequence containing the search results.</returns>
		public static IObservable<AppointmentsSearchEventArgs> SearchAppointments(DateTime startTimeInclusive, DateTime endTimeInclusive)
		{
			Contract.Ensures(Contract.Result<IObservable<AppointmentsSearchEventArgs>>() != null);

			return Appointments.SearchObservable(startTimeInclusive, endTimeInclusive);
		}

		/// <summary>
		/// Asynchronously searches for appointments that occur between the specified start date and time and end date and time, 
		/// from the specified data source.
		/// </summary>
		/// <param name="startTimeInclusive">The start date and time to use to search for appointments.</param>
		/// <param name="endTimeInclusive">The end date and time to use to search for appointments.</param>
		/// <param name="account">The data source to search for appointments.</param>
		/// <returns>A singleton observable sequence containing the search results.</returns>
		public static IObservable<AppointmentsSearchEventArgs> SearchAppointments(DateTime startTimeInclusive, DateTime endTimeInclusive, Account account)
		{
			Contract.Ensures(Contract.Result<IObservable<AppointmentsSearchEventArgs>>() != null);

			return Appointments.SearchObservable(startTimeInclusive, endTimeInclusive, account);
		}

		/// <summary>
		/// Asynchronously searches for appointments that occur between the specified start date and time and end date and time, 
		/// returning no more than the specified number of appointments.
		/// </summary>
		/// <param name="startTimeInclusive">The start date and time to use to search for appointments.</param>
		/// <param name="endTimeInclusive">The end date and time to use to search for appointments.</param>
		/// <param name="maximumItems">The maximum number of appointments to return.</param>
		/// <returns>A singleton observable sequence containing the search results.</returns>
		public static IObservable<AppointmentsSearchEventArgs> SearchAppointments(DateTime startTimeInclusive, DateTime endTimeInclusive, int maximumItems)
		{
			Contract.Ensures(Contract.Result<IObservable<AppointmentsSearchEventArgs>>() != null);

			return Appointments.SearchObservable(startTimeInclusive, endTimeInclusive, maximumItems);
		}

		/// <summary>
		/// Asynchronously searches for appointments that occur between the specified start date and time and end date and time, 
		/// from the specified data source, returning no more than the specified number of appointments.
		/// </summary>
		/// <param name="startTimeInclusive">The start date and time to use to search for appointments.</param>
		/// <param name="endTimeInclusive">The end date and time to use to search for appointments.</param>
		/// <param name="maximumItems">The maximum number of appointments to return.</param>
		/// <param name="account">The data source to search for appointments.</param>
		/// <returns>A singleton observable sequence containing the search results.</returns>
		public static IObservable<AppointmentsSearchEventArgs> SearchAppointments(DateTime startTimeInclusive, DateTime endTimeInclusive, int maximumItems, Account account)
		{
			Contract.Ensures(Contract.Result<IObservable<AppointmentsSearchEventArgs>>() != null);

			return Appointments.SearchObservable(startTimeInclusive, endTimeInclusive, maximumItems, account);
		}
		#endregion
	}
}